﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Diagnostics;

namespace Qreed.Drawing.Drawing2D
{
    public class Figure2D 
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="Shape2D"/> class.
        /// </summary>
        /// <param name="gp">The gp.</param>
        public Figure2D(GraphicsPath gp)
        {
            // 2D vector location provided by GraphicsPath are with an inverted Y because the upper left corner is 0.

            List<Polygon2D> substractionList = new List<Polygon2D>();

            for (int start = 0, i = 0; i < gp.PathPoints.Length; i++)
            {
                if((gp.PathTypes[i] & 0x80) == 0x80) // Segment closed
                {
                    Polygon2D segment = new Polygon2D(gp.PathPoints, start, i - start + 1);

                    if (segment.WindingOrder == WindingOrder.CounterClockWise)
                        substractionList.Add(segment);
                    else
                        _polygons.Add(segment);

                    start = i + 1;

                    Debug.WriteLine(string.Format("Polygon {0:00}: {1:0000} vertices {2} {3}", _polygons.Count - 1, segment.Count, segment.SegmentType, segment.WindingOrder));
                }
            }

            foreach (Polygon2D polygon in substractionList)
                Substract(polygon);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="Shape2D"/> class.
        /// </summary>
        public Figure2D()
        {
        }

        /// <summary>
        /// Triangulates this instance.
        /// </summary>
        public void Triangulate()
        {
            List<Polygon2D> triangles = new List<Polygon2D>();

            foreach (Polygon2D polygon in _polygons)
                triangles.AddRange(polygon.Triangulate());
            
            _polygons = triangles;
        }

        /// <summary>
        /// Adds the specified polygon.
        /// </summary>
        /// <param name="polygon">The polygon.</param>
        public void Add(Polygon2D polygon)
        {
            polygon.Validate();
            _polygons.Add(polygon);
        }

        /// <summary>
        /// Substracts the specified polygon.
        /// </summary>
        /// <param name="polygon">The polygon.</param>
        public void Substract(Polygon2D polygon)
        {
            polygon.Validate();

            foreach (Polygon2D poly in Polygons)
                poly.Substract(polygon);
        }

        private List<Polygon2D> _polygons = new List<Polygon2D>();
        /// <summary>
        /// Gets the polygons.
        /// </summary>
        /// <value>The polygons.</value>
        /// <remarks>The set is only available for serialization.</remarks>
        public List<Polygon2D> Polygons
        {
            get { return this._polygons; }
            set { _polygons = value; }
        }

        /// <summary>
        /// Gets the bounding rectangle for this figure.
        /// </summary>
        /// <returns>An rectangle containing the bounderies.</returns>
        public RectangleF GetBounds()
        {
            if (Polygons.Count == 0)
                return RectangleF.Empty;

            //RectangleF bounds = Polygons[0].GetBounds();

            PointF min;
            PointF max;

            Polygons[0].GetMinMaxPoints(out min, out max);

            for (int i = 1; i < Polygons.Count; i++)
            {
                Polygon2D polygon = Polygons[i];

                PointF minCurrent;
                PointF maxCurrent;

                polygon.GetMinMaxPoints(out minCurrent, out maxCurrent);

                min.X = Math.Min(min.X, minCurrent.X);
                min.Y = Math.Min(min.Y, minCurrent.Y);
                max.X = Math.Max(max.X, maxCurrent.X);
                max.Y = Math.Max(max.Y, maxCurrent.Y);
            }

            return new RectangleF(min, new SizeF(max.X - min.X, max.Y - min.Y));
        }
    }
}
